﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
using System.Resources;
using System.Collections;

namespace Kokomo.PeInspector.Reflection
{
	/// <summary>
	/// Provides functionality for extracting resources.
	/// </summary>
	/// <seealso cref="ExtractResources"/>
	public static class ResourceExtractor
	{
		/// <summary>
		/// Extracts the resources from an assembly.
		/// </summary>
		/// <param name="assembly">The assembly containing the resources.</param>
		/// <param name="options">Species options to control the operation.</param>
		/// <returns>A list of <see cref="AssemblyResource"/>s representing the 
		/// resources within the assembly.</returns>
		/// <seealso cref="ResourceExtractionOptions"/>
		/// <seealso cref="AssemblyResource"/>
		public static IEnumerable<AssemblyResource> ExtractResources(
			Assembly assembly,
			ResourceExtractionOptions options = ResourceExtractionOptions.None
			)
		{
			string assemblySimpleName = assembly.GetName().Name;
			string packResourceStreamName = assemblySimpleName + ".g.resources";

			List<AssemblyResource> resources = new List<AssemblyResource>();
			foreach (var manifestStreamName in assembly.GetManifestResourceNames())
			{
				byte[] data = null;
				using (Stream stream = assembly.GetManifestResourceStream(manifestStreamName))
				{
					if (stream != null)
					{
						int size = (int)stream.Length;
						data = new byte[size];

						stream.Read(data, 0, size);
					}
				}

				AssemblyResource manifestResource = new AssemblyManifestResource(assembly, manifestStreamName);
				resources.Add(manifestResource);

				if (manifestStreamName == packResourceStreamName)
				{
					MemoryStream packStream = new MemoryStream(data);
					ResourceReader resourceReader = new ResourceReader(packStream);
					foreach (DictionaryEntry resourceEntry in resourceReader)
					{
						string resourceKey = (string)resourceEntry.Key;
						Stream resourceStream = resourceEntry.Value as Stream;
						if (resourceStream != null)
						{
							AssemblyResource packResource = new AssemblyPackResource(manifestResource, resourceKey);
							resources.Add(packResource);
						}
					}
				}
			}

			return resources;
		}
	}
}
